﻿using Ant.BasicPlugIn.Data.Providers;
using Ant.Interface.Environment.Configuration;
using Ant.Interface.Environment.ShellBuilders;
using Ant.Interface.FileSystems.AppData;
using NHibernate;
using NHibernate.Cfg;

namespace Ant.BasicPlugIn.Data
{
    internal class SessionFactoryHolder : ISessionFactoryHolder
    {
        private readonly ShellSettings _shellSettings;
        private readonly ShellBlueprint _shellBlueprint;
        private readonly IDatabaseCacheConfiguration _cacheConfiguration;
        private readonly IDataServicesProviderFactory _dataServicesProviderFactory;
        private readonly IAppDataFolder _appDataFolder;
        private readonly ISessionConfigurationCache _sessionConfigurationCache;
        private ISessionFactory _sessionFactory;
        private Configuration _configuration;

        public SessionFactoryHolder(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IDatabaseCacheConfiguration cacheConfiguration, IDataServicesProviderFactory dataServicesProviderFactory, IAppDataFolder appDataFolder, ISessionConfigurationCache sessionConfigurationCache)
        {
            _shellSettings = shellSettings;
            _shellBlueprint = shellBlueprint;
            _cacheConfiguration = cacheConfiguration;
            _dataServicesProviderFactory = dataServicesProviderFactory;
            _appDataFolder = appDataFolder;
            _sessionConfigurationCache = sessionConfigurationCache;
        }

        public ISessionFactory GetSessionFactory()
        {
            lock (this)
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = BuildSessionFactory();
                }
            }
            return _sessionFactory;
        }

        public Configuration GetConfiguration()
        {
            lock (this)
            {
                if (_configuration == null)
                {
                    _configuration = BuildConfiguration();
                }
            }
            return _configuration;
        }

        private ISessionFactory BuildSessionFactory()
        {
            var config = GetConfiguration();
            var result = config.BuildSessionFactory();
            return result;
        }

        private Configuration BuildConfiguration()
        {
            var parameters = GetSessionFactoryParameters();

            var config = _sessionConfigurationCache.GetConfiguration(() =>
                _dataServicesProviderFactory
                    .CreateProvider(parameters)
                    .BuildConfiguration(parameters)
                .Cache(c => _cacheConfiguration.Configure(c))
            );

            return config;
        }

        public SessionFactoryParameters GetSessionFactoryParameters()
        {
            var shellPath = _appDataFolder.Combine("Sites", _shellSettings.Name);
            _appDataFolder.CreateDirectory(shellPath);

            var shellFolder = _appDataFolder.MapPath(shellPath);

            return new SessionFactoryParameters
            {
                Provider = _shellSettings.DataProvider,
                DataFolder = shellFolder,
                ConnectionString = _shellSettings.DataConnectionString,
                RecordDescriptors = _shellBlueprint.Records,
            };
        }
    }
}